package spl.army;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.text.ParseException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

import spl.utils.GlobalLogger;

public class Sim {
	
	private static final int ARGS = 4;
	
	private static final int MISSIONS_FILE = 0;
	private static final int SERGEANTS_FILE = 1;
	private static final int WAREHOUSE_FILE = 2;
	private static final int LOG_FILE = 3;
	
	private static final int WAIT_MAX_TIME_OUT = 5;
	
	/**
	 * @param args <missions_file> <sergeants_file> <items_file> <log_file>
	 */
	public static void main(String[] args) {
		String missionsFilePath;
		String sergeantsFilePath;
		String warehouseFilePath;
		String logFilePath;
		
		if (args.length != Sim.ARGS) {
			System.out.println("Usage: <missions_file> <sergeants_file> <items_file> <log_file>");
			return;
		} else {
			missionsFilePath = args[Sim.MISSIONS_FILE];
			sergeantsFilePath = args[Sim.SERGEANTS_FILE];
			warehouseFilePath = args[Sim.WAREHOUSE_FILE];
			logFilePath = args[Sim.LOG_FILE];			
		}
		
		try {
			/* initialize everything */
			GlobalLogger gl = new GlobalLogger(logFilePath);
			gl.logger.finest("Starting Simulation!");
			
			Board.initBoardFromPropFile(missionsFilePath);
			Warehouse.initWarehouseFromFile(warehouseFilePath);
			ChiefOfStaff.initSergeantsFromPropFile(sergeantsFilePath);
		} catch (FileNotFoundException e) {
			System.out.println("File IO Error... one of the files does not exist...");
			return;
		} catch (IOException e) {
			System.out.println("File IO Error... perhaps no permissions...");
			return;
		} catch (ParseException e) {
			System.out.println("File Syntax Error");
			return;
		}
		
		// Main threads holder: Observer and ChiefOfStaff. 
		ExecutorService warThreads = Executors.newFixedThreadPool(2);
 
		Future<?> observerFuture = warThreads.submit(new Observer());
		warThreads.submit(new ChiefOfStaff());
		
		// No more threads are accepted
		warThreads.shutdown();
		
		try {
			observerFuture.get();
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (ExecutionException e) {
			e.printStackTrace();
		}
		
		// Cleanup threads
		try {
			if (!warThreads.awaitTermination(WAIT_MAX_TIME_OUT, TimeUnit.SECONDS)) {
				warThreads.shutdownNow(); // Cancel currently executing tasks
				// Check if cancel is successful
				if (!warThreads.awaitTermination(1, TimeUnit.SECONDS))
		           System.err.println("Pool did not terminate");
		     }
		} catch (InterruptedException ie) {
			// (Re-)Cancel if current thread also interrupted
			warThreads.shutdownNow();
			 // Preserve interrupt status
			Thread.currentThread().interrupt();
		}
	}

}
